/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jmediaplayer;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import java.util.logging.*;
import javax.imageio.ImageIO;
import javax.media.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.*;
import org.jaudiotagger.tag.*;

/**
 * JPlayerBackground class
 * @author Duy Nguyen
 */
class JPlayerBackground extends Component {

    BufferedImage m_BackgroundImg;

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(420, 200);
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(m_BackgroundImg, 0, 0, null);
    }

    public JPlayerBackground() {
        try {
            URL url = getClass().getClassLoader().getResource(Constants.BackgroundPath);
            m_BackgroundImg = ImageIO.read(url);
        } catch (IOException ioex) {
        }
    }
}

/**
 * JPlayer class
 * @author Duy Nguyen
 */
public class JPlayer
        extends JPanel
        implements ActionListener,
        ControllerListener,
        Runnable,
        ChangeListener {

    private JLabel m_SongTitleLabel;
    private JLabel m_SongArtistLabel;
    private JLabel m_SongAlbumLabel;
    private JButton m_PlayPauseButton;
    private JButton m_PreviousButton;
    private JButton m_NextButton;
    private JButton m_StopButton;
    private JButton m_VolumeButton;
    private JButton m_RepeatButton;
    private JButton m_ShuffleButton;
    private JButton m_PlaylistToggleButton;
    private JSlider m_VolumeSlider;
    private JProgressBar m_ProgressBar;
    private Player m_MediaPlayer;
    private Thread m_PlayingThread;
    private int m_MediaState = MEDIA_STOPPED;
    private int m_PlayingMode = JPlaylist.MODE_REPEAT_SHUFFLE;
    private boolean m_IsRepeat = false;
    private boolean m_IsShuffle = false;
    private JPlayerBackground m_Background;
    private AudioFile currentFile = null;
    private JPlaylist m_Playlist;
    /**
     * Static constant
     */
    public static final int PLAYER_WIDTH = 480;
    public static final int PLAYER_HEIGHT = 200;
    public static final int MEDIA_STARTED = 0;
    public static final int MEDIA_STOPPED = 1;
    public static final int MEDIA_PAUSED = 2;

    /**
     * Perfrom actions from components
     * Implements from ActionListenr interface
     */
    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();

        if (actionCommand != null) {
            if (actionCommand.equals(Constants.PlayPauseCommand)) {
                PlayPauseAction();
            } else if (actionCommand.equals(Constants.StopCommand)) {
                StopAction();
            } else if (actionCommand.equals(Constants.NextCommand)) {
                NextAction(false);
            } else if (actionCommand.equals(Constants.PreviousCommand)) {
                PreviousAction();
            } else if (actionCommand.equals(Constants.RepeatCommand)) {
                RepeatAction();
            } else if (actionCommand.equals(Constants.ShuffleCommand)) {
                ShuffleAction();
            } else if (actionCommand.equals(Constants.PlaylistToggleCommand)) {
                if (m_Playlist.isVisible()) {
                    m_Playlist.setVisible(false);

                } else {
                    m_Playlist.setVisible(true);
                }
                Container parent, next;
                parent = this;
                while ((next = parent.getParent()) != null) {
                    parent = next;
                }
                if (parent instanceof Window) {
                    Window window = (Window) parent;
                    window.pack();
                }
            }

        }
    }

    /**
     * Implements from ControllerListener
     */
    public void controllerUpdate(ControllerEvent ce) {
        if (ce instanceof RealizeCompleteEvent) {
            m_MediaPlayer.prefetch();
            m_ProgressBar.setString("Prefetching...");
        }
        if (ce instanceof PrefetchCompleteEvent) {
            Time time = m_MediaPlayer.getDuration();
            m_ProgressBar.setMaximum((int) time.getSeconds());
            m_ProgressBar.setValue(0);
            m_ProgressBar.setString("Playing");
            m_PlayingThread = new Thread(this);
            m_PlayingThread.start();
            m_MediaPlayer.getGainControl().setLevel(m_VolumeSlider.getValue() / 100.0f);
            m_MediaPlayer.start();
            m_MediaState = MEDIA_STARTED;
            m_PlayPauseButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.PauseIconPath)));
        }
        if (ce instanceof EndOfMediaEvent) {
//            StopAction(); // Dong nay co the luoc bo
            NextAction(true);
        }
    }

    /**
     * Implements from ChangeListener interface
     * @param e
     */
    public void stateChanged(ChangeEvent e) {
        if (m_MediaPlayer != null) {
            m_MediaPlayer.getGainControl().setLevel((float) m_VolumeSlider.getValue() / 100.0f);
        }
    }

    /**
     * Constructer
     */
    public JPlayer() {
        super();
        Initialize();
    }

    /**
     * Constructer
     * @param isDoubleBuffered
     */
    public JPlayer(boolean isDoubleBuffered) {
        super(isDoubleBuffered);
        Initialize();
    }

    /**
     * Constructer
     * @param layout
     */
    public JPlayer(LayoutManager layout) {
        super(layout);
        Initialize();
    }

    /**
     * Constructer
     * @param layout
     * @param isDoubleBuffered
     */
    public JPlayer(LayoutManager layout, boolean isDoubleBuffered) {
        super(layout, isDoubleBuffered);
        Initialize();
    }

    /**
     * Implements from Runnable interface
     * Use this to update progress bar when music playing
     */
    public void run() {
        while (m_PlayingThread != null) {
            while (m_MediaPlayer != null) {
                Time time = m_MediaPlayer.getMediaTime();
                m_ProgressBar.setValue((int) time.getSeconds());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException iex) {
                }
            }
        }
    }

    /**
     * Action for PlayPause command
     */
    private void PlayPauseAction() {

        if (m_MediaState == MEDIA_STOPPED || m_MediaState == MEDIA_PAUSED) {
            if (currentFile != null) {
                PlayAction(currentFile);
            } else {
                Object obj = m_Playlist.getPlayingFile();
                if (obj == null) {
                    m_Playlist.setPlayingIndex(0);
                    obj = m_Playlist.getPlayingFile();
                }
                if (obj != null) {
                    if (obj instanceof AudioFile) {
                        PlayAction((AudioFile) obj);
                    }
                }
            }
        } else if (m_MediaState == MEDIA_STARTED) {
            PauseAction();
        }
    }

    /**
     * Action for Play command
     * @param file is the audio file which want to play
     */
    public void PlayAction(AudioFile file) {
        if (file != null
                && (m_MediaPlayer == null || file != currentFile)) {
            if (m_MediaPlayer != null) {
                m_MediaPlayer.close();
            }
            try {
                URL fileURL = file.getFile().toURI().toURL();
                currentFile = file;
                displayFileTags();
                MediaLocator locator = new MediaLocator(fileURL);
                m_MediaPlayer = Manager.createPlayer(locator);
                m_MediaPlayer.addControllerListener(this);
                m_ProgressBar.setString("Realizing ....");
                m_MediaPlayer.realize();
            } catch (MalformedURLException ex) {
            } catch (NoPlayerException ex) {
            } catch (IOException ex) {
            }
        } else {
            m_MediaPlayer.start();
            m_ProgressBar.setString("Playing");
            m_MediaState = MEDIA_STARTED;
            m_PlayPauseButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.PauseIconPath)));
        }
    }

    /**
     * Action for Pause command
     */
    private void PauseAction() {
        if (m_MediaPlayer != null) {
            m_MediaPlayer.stop();
            m_ProgressBar.setString("Paused");
            m_MediaState = MEDIA_PAUSED;
            m_PlayPauseButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.PlayIconPath)));
        }
    }

    /**
     * Action for Stop command
     */
    public void StopAction() {
        if (m_MediaPlayer != null) {
            m_MediaPlayer.removeControllerListener(this);
            m_MediaPlayer.stop();
            m_MediaPlayer.close();
            m_MediaPlayer = null;
            m_MediaState = MEDIA_STOPPED;
        }
        if (m_PlayingThread != null) {
            m_PlayingThread = null;
        }
        m_ProgressBar.setValue(0);
        m_ProgressBar.setString("");
        m_PlayPauseButton.setIcon(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.PlayIconPath)));
        currentFile = null;
    }

    /**
     * Action for Next command. This command is dependent on playing mode
     */
    private void NextAction(boolean auto) {
        if (m_Playlist != null) {
            m_Playlist.navigateNext(this.m_PlayingMode, auto);
        }
    }

    /**
     * Action for Previous command. This command is dependent on playing mode
     */
    private void PreviousAction() {
        if (m_Playlist != null) {
            m_Playlist.navigatePrevious(this.m_PlayingMode);
        }
    }

    /**
     * Action for Repeat command. After determine repeat mode, call ProcessPlayingMode
     * for determining playing mode
     */
    private void RepeatAction() {
        if (m_IsRepeat == false) {
            m_IsRepeat = true;
            m_RepeatButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.RepeatEnablePath)));
        } else {
            m_IsRepeat = false;
            m_RepeatButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.RepeatDisablePath)));
        }
        ProcessPlayingMode();
    }

    /**
     * Action for Shuffle command. After determine shuffle mode, call ProcessPlayingMode
     * for determinig playing mode
     */
    private void ShuffleAction() {
        if (m_IsShuffle == false) {
            m_IsShuffle = true;
            m_ShuffleButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.ShuffleEnablePath)));
        } else {
            m_IsShuffle = false;
            m_ShuffleButton.setIcon(new ImageIcon(
                    getClass().getClassLoader().getResource(Constants.ShuffleDisablePath)));
        }
        ProcessPlayingMode();
    }

    private void ProcessPlayingMode() {
        if (m_IsRepeat && m_IsShuffle) {
            m_PlayingMode = JPlaylist.MODE_REPEAT_SHUFFLE;
        } else if (m_IsRepeat && !m_IsShuffle) {
            m_PlayingMode = JPlaylist.MODE_REPEAT;
        } else if (!m_IsRepeat && m_IsShuffle) {
            m_PlayingMode = JPlaylist.MODE_SHUFFLE;
        } else {
            m_PlayingMode = JPlaylist.MODE_NORMAL;
        }
    }

    /**
     * If audio file has tag, load and display them on player
     */
    private void displayFileTags() {
        AudioFile af = null;
        try {
            af = AudioFileIO.read(currentFile.getFile());
        } catch (CannotReadException ex) {
            Logger.getLogger(JPlayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(JPlayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TagException ex) {
            Logger.getLogger(JPlayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ReadOnlyFileException ex) {
            Logger.getLogger(JPlayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidAudioFrameException ex) {
            Logger.getLogger(JPlayer.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (af != null) {
            Tag tag = af.getTag();
            if (tag != null) {
                m_SongTitleLabel.setText(JPlaylist.getTagTitle(af));
                m_SongArtistLabel.setText(tag.getFirst(FieldKey.ARTIST));
                m_SongAlbumLabel.setText(tag.getFirst(FieldKey.ALBUM));
            } else {
                m_SongTitleLabel.setText(af.getFile().getName());
                m_SongArtistLabel.setText("");
                m_SongAlbumLabel.setText("");
            }
        } else {
            m_SongTitleLabel.setText("");
            m_SongArtistLabel.setText("");
            m_SongAlbumLabel.setText("");
        }
    }

    private void Initialize() {
        this.setLayout(null);
        this.setPreferredSize(new Dimension(PLAYER_WIDTH, PLAYER_HEIGHT));

        // Initialize song title
        m_SongTitleLabel = new JLabel(Constants.SongTitleDefault);
        m_SongTitleLabel.setFont(new Font(Constants.SongTitleFontName,
                Constants.SongTitleFontStyle,
                Constants.SontTitleFontSize));
        m_SongTitleLabel.setBounds(Constants.SongTitleX,
                Constants.SongTitleY,
                Constants.SongTitleWidth,
                Constants.SongTitleHeight);
        m_SongTitleLabel.setForeground(Color.white);
        this.add(m_SongTitleLabel);

        // Initialize song artist
        m_SongArtistLabel = new JLabel(Constants.SongArtistDefault);
        m_SongArtistLabel.setFont(new Font(Constants.SongArtistFontName,
                Constants.SongAlbumFontStyle,
                Constants.SontArtistFontSize));
        m_SongArtistLabel.setBounds(Constants.SongArtistX,
                Constants.SongArtistY,
                Constants.SongArtistWidth,
                Constants.SongArtistHeight);
        m_SongArtistLabel.setForeground(Color.white);
        this.add(m_SongArtistLabel);

        // Initialize song Album
        m_SongAlbumLabel = new JLabel(Constants.SongAlbumDefault);
        m_SongAlbumLabel.setFont(new Font(Constants.SongAlbumFontName,
                Constants.SongAlbumFontStyle,
                Constants.SontAlbumFontSize));
        m_SongAlbumLabel.setBounds(Constants.SongAlbumX,
                Constants.SongAlbumY,
                Constants.SongAlbumWidth,
                Constants.SongAlbumHeight);
        m_SongAlbumLabel.setForeground(Color.white);
        this.add(m_SongAlbumLabel);

        // Initialize Play/Pause button
        m_PlayPauseButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.PlayIconPath)));
        m_PlayPauseButton.setBounds(Constants.PlayPauseX,
                Constants.PlayPauseY,
                Constants.PlayPauseWidth,
                Constants.PlayPauseHeight);
        m_PlayPauseButton.setActionCommand(Constants.PlayPauseCommand);
        m_PlayPauseButton.addActionListener(this);
        // Set button background transparent
        m_PlayPauseButton.setBorderPainted(false);
        m_PlayPauseButton.setFocusPainted(false);
        m_PlayPauseButton.setContentAreaFilled(false);
        this.add(m_PlayPauseButton);

        // Initialize Previous button
        m_PreviousButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.PreviousIconPath)));
        m_PreviousButton.setBounds(Constants.PreviousX,
                Constants.PreviousY,
                Constants.PreviousWidth,
                Constants.PreviousHeight);
        m_PreviousButton.setActionCommand(Constants.PreviousCommand);
        m_PreviousButton.addActionListener(this);
        // Set button background transparent
        m_PreviousButton.setBorderPainted(false);
        m_PreviousButton.setFocusPainted(false);
        m_PreviousButton.setContentAreaFilled(false);
        this.add(m_PreviousButton);

        // Initialize Next button
        m_NextButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.NextIconPath)));
        m_NextButton.setBounds(Constants.NextX,
                Constants.NextY,
                Constants.NextWidth,
                Constants.NextHeight);
        m_NextButton.setActionCommand(Constants.NextCommand);
        m_NextButton.addActionListener(this);
        // Set button background transparent
        m_NextButton.setBorderPainted(false);
        m_NextButton.setFocusPainted(false);
        m_NextButton.setContentAreaFilled(false);
        this.add(m_NextButton);

        // Initialize Stop button
        m_StopButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.StopIconPath)));
        m_StopButton.setBounds(Constants.StopX,
                Constants.StopY,
                Constants.StopWidth,
                Constants.StopHeight);
        m_StopButton.setActionCommand(Constants.StopCommand);
        m_StopButton.addActionListener(this);
        // Set button background transparent
        m_StopButton.setBorderPainted(false);
        m_StopButton.setFocusPainted(false);
        m_StopButton.setContentAreaFilled(false);
        this.add(m_StopButton);

        // Initialize Repeat button
        m_RepeatButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.RepeatDisablePath)));
        m_RepeatButton.setBounds(Constants.RepeatX,
                Constants.RepeatY,
                Constants.RepeatWidth,
                Constants.RepeatHeight);
        m_RepeatButton.setActionCommand(Constants.RepeatCommand);
        m_RepeatButton.addActionListener(this);
        // Set button background transparent
        m_RepeatButton.setBorderPainted(false);
        m_RepeatButton.setFocusPainted(false);
        m_RepeatButton.setContentAreaFilled(false);
        this.add(m_RepeatButton);

        // Initialize Shuffle button
        m_ShuffleButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.ShuffleDisablePath)));
        m_ShuffleButton.setBounds(Constants.ShuffleX,
                Constants.ShuffleY,
                Constants.ShuffleWidth,
                Constants.ShuffleHeight);
        m_ShuffleButton.setActionCommand(Constants.ShuffleCommand);
        m_ShuffleButton.addActionListener(this);
        // Set button background transparent
        m_ShuffleButton.setBorderPainted(false);
        m_ShuffleButton.setFocusPainted(false);
        m_ShuffleButton.setContentAreaFilled(false);
        this.add(m_ShuffleButton);

        // Initialize Volume button
        m_VolumeButton = new JButton(new ImageIcon(
                getClass().getClassLoader().getResource(Constants.VolumeIconPath)));
        m_VolumeButton.setBounds(Constants.VolumeX,
                Constants.VolumeY,
                Constants.VolumeWidth,
                Constants.VolumeHeight);
        m_VolumeButton.setActionCommand(Constants.VolumeCommand);
        m_VolumeButton.addActionListener(this);
        // Set button background transparent
        m_VolumeButton.setBorderPainted(false);
//        m_VolumeButton.setFocusPainted(false);
        m_VolumeButton.setContentAreaFilled(false);
        this.add(m_VolumeButton);

        // Initialize volume slider
        m_VolumeSlider = new JSlider(0, 100);
        m_VolumeSlider.setBounds(Constants.VolumeSldX,
                Constants.VolumeSldY,
                Constants.VolumeSldWidth,
                Constants.VolumeSldHeight);
        m_VolumeSlider.addChangeListener(this);
        //m_VolumeSlider.setBackground(new Color(0,0,0,0));
        this.add(m_VolumeSlider);

        // Initialize progress bar
        m_ProgressBar = new JProgressBar(0, 100);
        m_ProgressBar.setBounds(Constants.ProgressBarX,
                Constants.ProgressBarY,
                Constants.ProgressBarWidth,
                Constants.ProgressBarHeight);
        m_ProgressBar.setStringPainted(true);
        m_ProgressBar.setFont(new Font("Arial", Font.PLAIN, 10));
        this.add(m_ProgressBar);

        m_PlaylistToggleButton = new JButton(
                new ImageIcon(
                getClass().getClassLoader().getResource(Constants.PlaylistTogglePath)));
        m_PlaylistToggleButton.setBounds(
                Constants.PlaylistToggleButtonX,
                Constants.PlaylistToggleButtonY,
                Constants.PlaylistToggleButtonWidth,
                Constants.PlaylistToggleButtonHeight);
        m_PlaylistToggleButton.setActionCommand(Constants.PlaylistToggleCommand);
        m_PlaylistToggleButton.addActionListener(this);
        m_PlaylistToggleButton.setToolTipText(Constants.PLTIP_TOGGLE);
        // Set button background transparent
        m_PlaylistToggleButton.setBorderPainted(false);
        m_PlaylistToggleButton.setContentAreaFilled(false);
        this.add(m_PlaylistToggleButton);

        // Initialize background
        m_Background = new JPlayerBackground();
        m_Background.setBounds(0, 0, PLAYER_WIDTH, PLAYER_HEIGHT);
        this.add(m_Background);

        ProcessPlayingMode();
    }

    public void setPlaylist(JPlaylist playlist) {
        this.m_Playlist = playlist;
    }
}
